import EncryptionTools.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.Arrays;
public class DES {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("Please input a 64-bit plaintext (16 hexadecimal characters): ");
        String plaintext = scanner.nextLine();
        if (plaintext.length() != 16 || !plaintext.matches("[0-9A-Fa-f]+")) {
            System.out.println("The input must be exactly 16 hexadecimal characters (64 bits)!");
            return;
        }

        System.out.println("Please input a 64-bit initial key (16 hexadecimal characters): ");
        String key = scanner.nextLine();
        if (key.length() != 16 || !key.matches("[0-9A-Fa-f]+")) {
            System.out.println("The input must be exactly 16 hexadecimal characters (64 bits)!");
            return;
        }

        byte[] plaintextBytes = hexStringToBinaryArray(plaintext);
        byte[] keyBytes = hexStringToBinaryArray(key);

        byte[] encrypted = encrypt(plaintextBytes, keyBytes);
        System.out.println("Encryption result: " + _64bytesToHex(encrypted));

        scanner.close();
    }

    public static byte[] encrypt(byte[] plaintext, byte[] key){
        byte[] permutedInput = InitialPermutation.applyInitialPermutation(plaintext);
        //Initial permutation

        byte[][] subKeys = KeySchedule.generateSubKeys(key);
        int count=1;

        byte[] left = new byte[32];
        byte[] right = new byte[32];
        System.arraycopy(permutedInput, 0, left, 0, 32);
        System.arraycopy(permutedInput, 32, right, 0, 32);

        for (int i = 0; i < 16; i++){

            byte[] rightExpanded = ExpansionPermutation.applyExpansionPermutation(right);
            //Expand to 48 bit to do xor with the sub key
            byte[] xorResult = XOR.xorOperation(rightExpanded, subKeys[i]);
            //xor operation
            byte[] sBoxOutput = SubstitutionBoxes.applySubstitution(xorResult);
            //Submit to 32 bit
            byte[] pBoxOutput = PermutationBox.applyPermutation(sBoxOutput);
            //Do the permutation again
            byte[] newRight = XOR.xorOperation(left, pBoxOutput);
            //Update the next right part

            left = right;
            right = newRight;
        }

        byte[] combined = new byte[64];
        System.arraycopy(right, 0, combined, 0, 32);
        System.arraycopy(left, 0, combined, 32, 32);
        byte[] finalOutput = FinalPermutation.applyFinalPermutation(combined);
        return finalOutput;
    }

    public static byte[] hexStringToBinaryArray(String hexInput) {
        // 计算所需的二进制位数
        StringBuilder binaryString = new StringBuilder();

        // 将每个十六进制字符转换为4位二进制
        for (char hexChar : hexInput.toCharArray()) {
            int value = Integer.parseInt(String.valueOf(hexChar), 16); // 解析十六进制字符
            String binaryChar = String.format("%4s", Integer.toBinaryString(value)).replace(' ', '0'); // 转换为4位二进制
            binaryString.append(binaryChar);
        }

        // 创建64位的字节数组
        byte[] binaryArray = new byte[64];
        for (int i = 0; i < 64; i++) {
            // 如果二进制字符串不足64位，填充0
            if (i < binaryString.length()) {
                binaryArray[i] = (byte) (binaryString.charAt(i) - '0');
            } else {
                binaryArray[i] = 0; // 填充为0
            }
        }

        return binaryArray;
    }

    public static String _32bytesToHex(byte[] bytes)
    {
        StringBuilder stringBuilder = new StringBuilder();
        long value = 0;
        for (int j = 0; j < 32; j++) {
            value <<= 1;
            value |= (bytes[j] & 0x01);
        }
        stringBuilder.append(String.format("%08x", value));
        return stringBuilder.toString();
    }

    public static String _48bytesToHex(byte[] bytes)
    {
        StringBuilder stringBuilder = new StringBuilder();
        long value = 0;
        for (int j = 0; j < 48; j++) {
            value <<= 1;
            value |= (bytes[j] & 0x01);
        }
        stringBuilder.append(String.format("%012x", value));
        return stringBuilder.toString();
    }
    public static String _64bytesToHex(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        long value = 0;
        for (int j = 0; j < 64; j++) {
            value <<= 1;
            value |= (bytes[j] & 0x01);
        }
        stringBuilder.append(String.format("%016x", value));
        return stringBuilder.toString();
    }
}

